require "import"
import "android.widget.*"
import "android.view.*"
import "android.content.Context"
import "android.content.Intent"
import "java.util.Locale"
import "android.speech.SpeechRecognizer"
import "android.speech.RecognitionListener"
import "android.speech.RecognizerIntent"
import "android.speech.tts.TextToSpeech"
import "android.speech.tts.UtteranceProgressListener"
import "android.view.accessibility.AccessibilityNodeInfo"
import "android.os.Bundle"

local context = service
local tts = nil
local isTtsReady = false
local isLooping = true
local lastSpokenSentence = "" 

function string:trim()
  return self:match("^%s*(.-)%s*$")
end

function fixHamza(text)
  local replacements = {
    ["^丕賱賶"] = "廿賱賶", [" 丕賱賶"] = " 廿賱賶",
    ["^丕賳 "] = "廿賳 ", [" 丕賳 "] = " 廿賳 ",
    ["^丕賳賰"] = "廿賳賰", [" 丕賳賰"] = " 廿賳賰",
    ["^丕賳賳丕"] = "廿賳賳丕", [" 丕賳賳丕"] = " 廿賳賳丕",
    ["^丕匕丕"] = "廿匕丕", [" 丕匕丕"] = " 廿匕丕",
    ["^丕乇爻丕賱"] = "廿乇爻丕賱", [" 丕乇爻丕賱"] = " 廿乇爻丕賱",
    ["^丕賲賱丕亍"] = "廿賲賱丕亍", [" 丕賲賱丕亍"] = " 廿賲賱丕亍",
    ["^丕賳爻丕賳"] = "廿賳爻丕賳", [" 丕賳爻丕賳"] = " 廿賳爻丕賳",
    ["^丕賷賲丕賳"] = "廿賷賲丕賳", [" 丕賷賲丕賳"] = " 廿賷賲丕賳",
    ["^丕爻賱丕賲"] = "廿爻賱丕賲", [" 丕爻賱丕賲"] = " 廿爻賱丕賲",
    ["^丕賰乇丕賲"] = "廿賰乇丕賲", [" 丕賰乇丕賲"] = " 廿賰乇丕賲",
    ["^丕禺賱丕氐"] = "廿禺賱丕氐", [" 丕禺賱丕氐"] = " 廿禺賱丕氐",
    ["^丕毓賱丕賳"] = "廿毓賱丕賳", [" 丕毓賱丕賳"] = " 廿毓賱丕賳",
    ["^丕毓丿丕丿"] = "廿毓丿丕丿", [" 丕毓丿丕丿"] = " 廿毓丿丕丿",
    ["^丕丿丕乇丞"] = "廿丿丕乇丞", [" 丕丿丕乇丞"] = " 廿丿丕乇丞",
    ["^丕噩乇丕亍"] = "廿噩乇丕亍", [" 丕噩乇丕亍"] = " 廿噩乇丕亍",
    ["^丕鬲賲丕賲"] = "廿鬲賲丕賲", [" 丕鬲賲丕賲"] = " 廿鬲賲丕賲",
    ["^廿賱賷賴"] = "廿賱賷賴", [" 廿賱賷賴"] = " 廿賱賷賴",
    ["^丕丨賲丿"] = "兀丨賲丿", [" 丕丨賲丿"] = " 兀丨賲丿",
    ["^丕賳鬲"] = "兀賳鬲", [" 丕賳鬲"] = " 兀賳鬲",
    ["^丕賳丕"] = "兀賳丕", [" 丕賳丕"] = " 兀賳丕",
    ["^丕賷囟丕"] = "兀賷囟丕賸", [" 丕賷囟丕"] = " 兀賷囟丕賸"
  }
  
  for wrong, right in pairs(replacements) do
    text = text:gsub(wrong, right)
  end
  
  return text
end

function substituteWords(text)
  text = fixHamza(text)
  
  local replacements = {
    ["丕賱賱賴"] = "丕賱賱賾賴", ["丕賱賱賾賴"] = "丕賱賱賾賴",
    ["賴匕賴"] = "賴匕賴", ["賮賷賴"] = "賮賷賴", ["毓賱賷賴"] = "毓賱賷賴", ["賲賳賴"] = "賲賳賴",
    ["丕賲乇丕賴"] = "丕賲乇丕賴", ["丕賱賮賯賷賴"] = "丕賱賮賯賷賴", ["丕賱賮賯賴"] = "丕賱賮賯賴",
    ["亘乇賰丕鬲賴"] = "亘乇賰丕鬲賴", ["賵亘乇賰丕鬲賴"] = "賵亘乇賰丕鬲賴",
    ["丿乇丕噩賴 賳丕乇賷賴"] = "丿乇丕噩丞 賳丕乇賷丞",
    ["噩賲賷賱賴"] = "噩賲賷賱丞"
  }
  
  for wrong, right in pairs(replacements) do
    text = text:gsub(wrong, right)
  end

  text = text:gsub("([^賱])賴 ", "%1丞 "):gsub("([^賱])賴%.", "%1丞."):gsub("([^賱])賴,", "%1丞,"):gsub("([^賱])賴$", "%1丞")
  
  local forceHeh = {
    ["賴匕賴"] = "賴匕賴", ["賮賷賴"] = "賮賷賴", ["毓賱賷賴"] = "毓賱賷賴", ["賲賳賴"] = "賲賳賴",
    ["丕賲乇丕賴"] = "丕賲乇丕賴", ["丕賱賮賯賷賴"] = "丕賱賮賯賷賴", ["丕賱賮賯賴"] = "丕賱賮賯賴", ["亘乇賰丕鬲賴"] = "亘乇賰丕鬲賴",
    ["丕賱賱賾賴"] = "丕賱賱賾賴"
  }
  
  for k, v in pairs(forceHeh) do 
    text = text:gsub(k:gsub("賴", "丞"), v) 
  end

  return text
end

function applyEmoji(targetText)
  local edit = service.getEditText()
  if not edit or targetText == "" then return end
  
  local emojiMap = {
    ["丕賱爻賱丕賲"] = "馃檶馃尮", ["爻賱丕賲"] = "馃憢",
    ["丿賮"] = "馃", ["賳丕賷"] = "馃幏", ["噩賷鬲丕乇"] = "馃幐", ["毓賵丿"] = "馃幓", ["胤亘賱"] = "馃",
    ["胤亘賷亘"] = "馃懆鈥嶁殨锔�", ["丕爻賳丕賳"] = "馃Ψ", ["噩賱丿"] = "馃Φ",
    ["兀爻丿"] = "馃", ["賯胤"] = "馃惐", 
    ["胤丕卅乇丞"] = "鉁堬笍", ["胤丕卅乇賴"] = "鉁堬笍", ["亘丕禺乇丞"] = "馃殺", ["亘丕禺乇賴"] = "馃殺", ["爻賮賷賳丞"] = "馃洺锔�", ["爻賮賷賳賴"] = "馃洺锔�",
    ["爻賷丕乇丞"] = "馃殫", ["爻賷丕乇賴"] = "馃殫", ["賯胤丕乇"] = "馃殕", ["丿乇丕噩丞 賳丕乇賷丞"] = "馃弽锔�", ["爻賮乇"] = "馃彇锔忊湀锔�",
    ["丕賱噩夭丕卅乇"] = "馃嚛馃嚳", ["丕賱賲睾乇亘"] = "馃嚥馃嚘", ["鬲賵賳爻"] = "馃嚬馃嚦", ["賱賷亘賷丕"] = "馃嚤馃嚲", ["賲賵乇賷鬲丕賳賷丕"] = "馃嚥馃嚪",
    ["賮賱爻胤賷賳"] = "馃嚨馃嚫", ["丕賱爻毓賵丿賷丞"] = "馃嚫馃嚘", ["丕賱賰賵賷鬲"] = "馃嚢馃嚰", ["丕賱毓乇丕賯"] = "馃嚠馃嚩", ["丕賱賷賲賳"] = "馃嚲馃嚜",
    ["丨亘"] = "鉂わ笍", ["丕丨亘賰"] = "馃馃槏", ["毓卮賯"] = "馃挒", ["賯賱亘"] = "馃挅",
    ["丨夭賳"] = "馃槩", ["丨夭賷賳"] = "馃様", ["鬲亘賰賷"] = "馃槶", ["囟賷賯"] = "馃挃",
    ["爻賷賮"] = "鈿旓笍", ["爻賷賵賮"] = "馃棥锔�",
    ["賲胤乇賯丞"] = "馃敤", ["賲胤乇賯賴"] = "馃敤",
    ["賮兀爻"] = "馃獡", ["賮丕爻"] = "馃獡",
    ["賱賷賱"] = "馃寖", ["丕賱賱賷賱"] = "馃寣", ["賲爻丕亍"] = "馃寙",
    ["賳賴丕乇"] = "馃彊锔�", ["丕賱賳賴丕乇"] = "馃寗", ["氐亘丕丨"] = "鈽�锔�",
    ["卮賲爻"] = "鈽�锔�", ["丕賱卮賲爻"] = "馃尀",
    ["賯賲乇"] = "馃寵", ["丕賱賯賲乇"] = "馃寱", ["賴賱丕賱"] = "馃寵",
    ["賰爻賵賮"] = "馃寫鈽�锔�", ["禺爻賵賮"] = "馃寶", ["賳噩賲"] = "猸�", ["賳噩賵賲"] = "鉁�",
    ["卮噩乇"] = "馃尦", ["兀卮噩丕乇"] = "馃尣", ["睾丕亘丞"] = "馃尣馃尦",
    ["賵乇丿"] = "馃尮", ["賵乇賵丿"] = "馃拹", ["夭賴乇丞"] = "馃尭", ["夭賴賵乇"] = "馃尫",
    ["爻毓乇"] = "馃挵", ["兀爻毓丕乇"] = "馃捁", ["賮賱賵爻"] = "馃挼", ["賲丕賱"] = "馃捀", ["丿賵賱丕乇"] = "馃挷", ["匕賴亘"] = "馃獧",
    ["毓賲賱丞"] = "馃獧", ["毓賲賱丕鬲"] = "馃挶", ["賷賵乇賵"] = "馃挾", ["賷賳"] = "馃挻", ["噩賳賷賴"] = "馃挿", ["丿賷賳丕乇"] = "馃挵", ["賳賯賵丿"] = "馃挼馃獧",
    ["噩賲賷賱丞"] = "鉁�", ["噩賲賷賱賴"] = "鉁�"
  }
  
  local finalEmoji = ""
  for word, emoji in pairs(emojiMap) do
    if targetText:find(word) then finalEmoji = finalEmoji .. emoji end
  end
  
  if finalEmoji ~= "" then 
    service.insertText(edit, " " .. finalEmoji) 
  else 
    service.insertText(edit, " 鉁�") 
  end
end

function readFullEditContent()
  local edit = service.getEditText()
  if edit then
    local content = edit.getText()
    if content and content ~= "" then
      readText(content)
    end
  end
end

function clearText()
  local edit = service.getEditText()
  if edit then
    local arguments = Bundle()
    arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, "")
    edit.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments)
  end
end

function directSend()
  local root = service.getRootInActiveWindow()
  if not root then return end
  local nodes = root.findAccessibilityNodeInfosByViewId("com.whatsapp:id/send")
  if nodes == nil or nodes.isEmpty() then
    nodes = root.findAccessibilityNodeInfosByViewId("org.telegram.messenger:id/chat_send_button")
  end
  if nodes ~= nil and not nodes.isEmpty() then
    nodes.get(0).performAction(AccessibilityNodeInfo.ACTION_CLICK)
  end
end

function initTTS()
  tts = TextToSpeech(context, {
    onInit = function(status)
      if status == TextToSpeech.SUCCESS then
        isTtsReady = true
        local listener = luajava.override(UtteranceProgressListener, {
          onDone = function(id) if isLooping then iniciarDictado() end end,
          onError = function(id) if isLooping then iniciarDictado() end end
        })
        tts.setOnUtteranceProgressListener(listener)
      end
    end
  })
end

function readText(text)
  if tts and isTtsReady and text ~= "" then
    tts.speak(text, TextToSpeech.QUEUE_FLUSH, nil, "dict_id")
  elseif isLooping then iniciarDictado() end
end

function iniciarDictado()
  if not SpeechRecognizer.isRecognitionAvailable(service) or not isLooping then return end
  task(500, function()
    local recognizer = SpeechRecognizer.createSpeechRecognizer(service)
    local intent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
    intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, "ar-SA")
    local listener = {
      onResults = function(results)
        local data = results.getStringArrayList(SpeechRecognizer.RESULTS_RECOGNITION)
        if data and not data.isEmpty() then
          local rawText = luajava.astable(data)[1]:trim()
          
          if rawText:find("丕賱爻賱丕賲 毓賱賷賰賲 賵乇丨賲丞 丕賱賱賴 鬲毓丕賱賶 賵亘乇賰丕鬲賴") then
            local processed = substituteWords(rawText)
            local edit = service.getEditText()
            if edit then service.insertText(edit, " " .. processed) end
            readFullEditContent()
          elseif rawText == "鬲賵賯賮" then
            isLooping = false
          elseif rawText == "丕賳鬲馗乇" or rawText == "鬲賵賯賮 賯賱賷賱丕" or rawText == "鬲賵賯賮 賯賱賷賱丕賸" then
            task(3000, function() if isLooping then iniciarDictado() end end)
          elseif rawText == "賲爻丨" then
            clearText()
            if isLooping then iniciarDictado() end
          elseif rawText == "爻胤乇 噩丿賷丿" then
            local edit = service.getEditText()
            if edit then service.insertText(edit, "\n") end
            if isLooping then iniciarDictado() end
          elseif rawText == "丕賷賲賵噩賷" or rawText == "丕賱丕賷賲賵噩賷" then
            applyEmoji(lastSpokenSentence) 
            if isLooping then iniciarDictado() end
          elseif rawText == "廿乇爻丕賱" or rawText == "丕乇爻丕賱" then
            directSend()
            isLooping = false
          else
            lastSpokenSentence = rawText 
            local processed = substituteWords(rawText)
            local edit = service.getEditText()
            if edit then service.insertText(edit, " " .. processed) end
            readText(processed)
          end
        else
          if isLooping then iniciarDictado() end
        end
        recognizer.destroy()
      end,
      onError = function()
        recognizer.destroy()
        if isLooping then task(1000, iniciarDictado) end
      end
    }
    recognizer.setRecognitionListener(luajava.createProxy("android.speech.RecognitionListener", listener))
    recognizer.startListening(intent)
  end)
end

initTTS()
if service.getEditText() then iniciarDictado() end
return true